#include "DBQuery.h"
#include <cstring>

#ifdef _DEBUG
#define debug_printf printf
#else
#define debug_printf()
#endif

std::string EscapeString(std::string str) /* Based on escape_string_for_mysql implementation in mysys/charset.c */
{
	std::string ret = "";
	int len = str.length();
	int toLen = len * 2 + 1;
	char* to = new char[toLen]; // reserve enough space to escape every character plus a null-terminator
	const char* from = str.c_str();
	char escape = 0;
	memset(to, 0, toLen * sizeof(char));
	for (int i = 0, j = 0; j < len; j++)
	{
		escape = 0;
		switch(from[j])
		{
		case 0:
			escape = '0';
			break;
		case '\n':
			escape = 'n';
			break;
		case '\r':
			escape = 'r';
			break;
		case '\\':
			escape = '\\';
			break;
		case '\'':
			escape = '\'';
			break;
		case '"':
			escape = '"';
			break;
		case '\032':
			escape = 'Z';
			break;
		}
		if (escape)
		{
			to[i++] = '\\';
			to[i++] = escape;
		}
		else
		{
			to[i++] = from[j];
		}
	}
	ret = to;
	delete to;
	return ret;
}

DBQuery::~DBQuery()
{
	std::map<int, DBQuery::Data*>::iterator iter = boundData.begin(), end = boundData.end();
	for (; iter != end; iter++)
	{
		if (iter->second && iter->second->Type == 's')
		{
			delete iter->second->String;
		}
	}
}

void DBQuery::SetFormatString(std::string str)
{
	fmtString = str;
}

std::string DBQuery::GetFormatString() const
{
	return fmtString;
}

std::string DBQuery::GetQuery()
{
	const char escape[] = "'\"";
	char chars[256];
	int i, j, k;
	Data* data = NULL;
	std::string temp = "";
	std::string query = fmtString;
	i = query.find('{');
	j = query.find('}', i);
	memset(chars, 0, 256 * sizeof(char));
	while (j > i)
	{
		temp = query.substr(i, j - i + 1);
		sscanf(temp.c_str(), "{%d}", &k);
		data = boundData[k];
		if (data != NULL)
		{
			if (data->Type == 'i')
			{
				sprintf(chars, "%d", data->Int);
				temp = chars;
			}
			else if (data->Type == 'f')
			{
				sprintf(chars, "%f", data->Float);
				temp = chars;
			}
			else if (data->Type == 's')
			{
				temp = data->String;
				temp = EscapeString(temp);
			}
		}
		query.replace(i, j - i + 1, temp);
		i = (int)query.find('{', i + temp.length()); // find next '{' after insert
		j = (int)query.find('}', i);
		memset(chars, 0, 256 * sizeof(char));
	}
	return query;
}

void DBQuery::BindData(int index, int d)
{
	Data* data = new Data;
	data->Int = d;
	data->Type = 'i';
	boundData[index] = data;
}

void DBQuery::BindData(int index, std::string d)
{
	Data* data = new Data;
	data->String = new char[d.length() + 1]; // may need to add a NULL-terminator
	memcpy(data->String, d.c_str(), d.length());
	data->String[d.length()] = 0;
	data->Type = 's';
	boundData[index] = data;
}

void DBQuery::BindData(int index, double d)
{
	Data* data = new Data;
	data->Float = d;
	data->Type = 'f';
	boundData[index] = data;
}

void DBQuery::Reset()
{
	fmtString = "";
	boundData.clear();
}